#include "opencv2\highgui\highgui.hpp"
#include "opencv2\imgproc\imgproc.hpp"
#include "opencv2\objdetect\objdetect.hpp"
#include <iostream>
#include <Windows.h>

const char WIN_TITLE[32] = "My First CV Window";
const char EDGE_DETECT[32] = "Edge Detection";
const char FACE_DETECT[32] = "Face Detection";


int main( int argc, const char** argv ) {

	FreeConsole();
	cv::VideoCapture vidCap(0);
	cv::CascadeClassifier ccFace;

	if ( !vidCap.isOpened() ) {
	
		std::cout << "ERROR: Camera cannot be loaded..." << std::endl;
		system("pause");
		return -1;
	}

	if ( !ccFace.load( "lbpcascade_frontalface.xml" ) ) {
		std::cout << "ERROR: Could not load FACE cascade..." << std::endl;
		system("pause");
		return -1;
	}

	cv::namedWindow( FACE_DETECT, CV_WINDOW_NORMAL );
	
	while(1) {
		cv::Mat matCam;
		cv::Mat matProc;
		bool bSuccess = vidCap.read(matCam);
		std::vector<cv::Rect> faces;
		cv::Point pnt(96, 28);
		cv::Point x3Loc;
		std::ostringstream strCentre;
		std::ostringstream strGrid;

		if ( !bSuccess ) {

			std::cout << "ERROR: Cannot read video stream..." << std::endl;
			break;
		}

		cv::cvtColor( matCam, matProc, CV_RGB2GRAY );
		cv::equalizeHist( matProc, matProc );
		ccFace.detectMultiScale( matProc, faces, 1.1, 2, CV_HAAR_SCALE_IMAGE, cv::Size( 30, 30 ) );

		if ( faces.size() > 0 ) {

			cv::Point pntCentreF( faces[0].x + faces[0].width/2, faces[0].y + faces[0].height/2 );
			cv::circle( matCam, pntCentreF, 0, cv::Scalar( 255, 0, 0 ), 3 );

			strCentre << "Nose Coords @ ( " << pntCentreF.x << ", " << pntCentreF.y << " )";

			x3Loc.x = pntCentreF.x/(matCam.cols/3);
			x3Loc.y = pntCentreF.y/(matCam.rows/3);
			strGrid << "Grid Loc @ ( " << x3Loc.x << ", " << x3Loc.y << " )";
		}

		cv::putText( matCam, strCentre.str(), pnt, CV_FONT_HERSHEY_PLAIN, 2, cv::Scalar::all(0), 3 );
		cv::putText( matCam, strCentre.str(), pnt, CV_FONT_HERSHEY_PLAIN, 2, cv::Scalar::all(255), 2 );

		pnt.y += 36;
		pnt.x += 78;
		
		cv::putText( matCam, strGrid.str(), pnt, CV_FONT_HERSHEY_PLAIN, 1.8, cv::Scalar::all(0), 2 );
		cv::putText( matCam, strGrid.str(), pnt, CV_FONT_HERSHEY_PLAIN, 1.8, cv::Scalar::all(255), 1 );

		cv::Point v1( matCam.cols/3, -1 );
		cv::Point v2( v1.x * 2, matCam.rows + 1 );
		cv::rectangle( matCam, v1, v2, cv::Scalar::all(0) );

		cv::Point h1( -1, matCam.rows/3 );
		cv::Point h2( matCam.cols + 1, h1.y * 2 );
		cv::rectangle( matCam, h1, h2, cv::Scalar::all(0) );

		cv::imshow( FACE_DETECT, matCam );

		if ( cv::waitKey(100) == 27 ) {
			
			std::cout << "Terminating program..." << std::endl;
			break;
		}
	}

	cv::destroyWindow( FACE_DETECT );

	return 0;
}


/********************LOADING AN IMAGE**************************
	FreeConsole();
	//cv::Mat matImg = cv::imread( "rooster.jpg", CV_LOAD_IMAGE_GRAYSCALE );
	cv::Mat matImg( 500, 1000, CV_8UC3, cv::Scalar(0, 0, 100) );

	if ( matImg.empty() ) {
	
		std::cout << "ERROR: Image cannot be loaded..." << std::endl;
		system("pause");
		return -1;
	}

	cv::namedWindow( WIN_TITLE, CV_WINDOW_NORMAL );
	cv::resizeWindow( WIN_TITLE, 512, 480 );
	cv::imshow( WIN_TITLE, matImg );

	cv::waitKey( 0 );
	cv::destroyWindow( WIN_TITLE );

	return 0;
**************************************************************/

/********************LOADING A WEBCAM**************************
	FreeConsole();
	cv::VideoCapture vidCap(0);

	if ( !vidCap.isOpened() ) {
	
		std::cout << "ERROR: Camera cannot be loaded..." << std::endl;
		system("pause");
		return -1;
	}

	std::cout << "Frame size: " << vidCap.get( CV_CAP_PROP_FRAME_WIDTH ) << "x" << vidCap.get( CV_CAP_PROP_FRAME_HEIGHT ) << std::endl;

	cv::namedWindow( WIN_TITLE, CV_WINDOW_NORMAL );
	cv::resizeWindow( WIN_TITLE, 512, 480 );
	
	while(1) {
		cv::Mat matFrame;
		bool bSuccess = vidCap.read(matFrame);

		if ( !bSuccess ) {

			std::cout << "ERROR: Cannot read video stream..." << std::endl;
			break;
		}

		cv::imshow( WIN_TITLE, matFrame );

		if ( cv::waitKey(30) == 27 ) {
			
			std::cout << "Terminating program..." << std::endl;
			break;
		}
	}

	cv::destroyWindow( WIN_TITLE );

	return 0;
**************************************************************/

/*********************EDGE DETECTION***************************
	FreeConsole();
	cv::VideoCapture vidCap(0);

	std::vector<cv::Vec3f> circles;

	if ( !vidCap.isOpened() ) {
	
		std::cout << "ERROR: Camera cannot be loaded..." << std::endl;
		system("pause");
		return -1;
	}

	std::cout << "Frame size: " << vidCap.get( CV_CAP_PROP_FRAME_WIDTH ) << "x" << vidCap.get( CV_CAP_PROP_FRAME_HEIGHT ) << std::endl;

	cv::namedWindow( EDGE_DETECT, CV_WINDOW_NORMAL );
	cv::resizeWindow( EDGE_DETECT, 512, 480 );
	
	while(1) {
		cv::Mat matCam;
		cv::Mat matEdge;
		bool bSwapSrc = true;
		bool bSuccess = vidCap.read(matCam);

		if ( !bSuccess ) {

			std::cout << "ERROR: Cannot read video stream..." << std::endl;
			break;
		}

		cv::cvtColor( matCam, matEdge, CV_RGB2GRAY );
		
		cv::GaussianBlur( matEdge, matEdge, cv::Size(5,5), 4, 4 );
		cv::GaussianBlur( matEdge, matEdge, cv::Size(5,5), 4, 4 );
		cv::GaussianBlur( matEdge, matEdge, cv::Size(5,5), 4, 4 );

		cv::HoughCircles( matEdge, circles, CV_HOUGH_GRADIENT, 1, matEdge.rows/256, 100, 100 );

		for ( UINT i = 0; i < circles.size(); ++i ) {
			cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
			int radius = cvRound(circles[i][2]);
			// circle center
			circle( matCam, center, 3, cv::Scalar(0,255,0), -1, 8, 0 );
			// circle outline
			circle( matCam, center, radius, cv::Scalar(0,0,255), 3, 8, 0 );
		}

		cv::imshow( EDGE_DETECT, matCam );

		if ( cv::waitKey(50) == 27 ) {
			
			std::cout << "Terminating program..." << std::endl;
			break;
		} else if ( cv::waitKey(50) == ' ' ) {
		
			bSwapSrc = !bSwapSrc;
		}
	}

	cv::destroyWindow( EDGE_DETECT );

	return 0;
**************************************************************/